#include "TokenTyp.h"
#include "Symtable.h"
#include "TokenHierarchy.h"
#include "Logger.h"
#include "ScannerFSM.h"
#include "stdlib.h"

#include <iostream>
#include <time.h>

#define BUFFER_BLOCK_SIZE 1024
#define SYMTABLE_ARRAY_SIZE 20000

#define DEBUG_MODE false

#define DEFAULT_INPUT "C:\\Dokumente und Einstellungen\\D4'M3Th0d\\Desktop\\SVN\\Scanner\\TESTFILES\\test6.txt"
#define DEFAULT_OUTPUT "test6_output.txt"

using namespace std;

// Beispiel Datei erzeugen
void createFile() {
	FileOutput* out = FileOutput::getInstance();
	out->setFile("test.txt");
	for( int i = 0; i < 1; i++) {
		out->writeLine("12345");
		out->writeLine("meineVariable := eineAndereVar ;");
		out->writeLine("test := 5 + 10;(* kommentar \n blablabl*)");
		out->writeLine("zahlReal := 1.2345E-5;");
		out->writeLine("e := d;");
		out->writeLine("e := 7239487;");
		out->writeLine("nochEineZahl := 13251.2321 ;");
		out->writeLine("(*test test test!)(* *)");
		out->writeLine("meineVariable := (b)*( 4)* (5 ) *( 6 );");
		out->writeLine("meineVariable := b ;");
		out->writeLine("4545 56");
	}
}

int main(int argc, char* const argv[]) {
	// Zeiger für Symboltabelle
	SymtableInterface* symtable	= 0;
	// Zeiger für Automaten
	ScannerFSMInterface* fsm	= 0;

	// Array für Standard Programmparameter
	char* argvDefault[3];

	// Wenn Programm im Debug Modus läuft und keine Parameter übergeben wurde, dann Standard Parameter setzen
	if (DEBUG_MODE && argc == 1)
	{
		// Anzahl der Parameter auf 3 setzen
		argc = 3;
	
		// Name des Programms setzen
		argvDefault[0] = argv[0];
		// Standard Input File setzen
		argvDefault[1] = (char*) DEFAULT_INPUT;
		// Standard Output File setzen
		argvDefault[2] = (char*) DEFAULT_OUTPUT;
		// Zeiger auf Vektor mit Standardwerten zeigen lassen
		argv = argvDefault;
	}

	//int i = 0;
	//double test = strtod("999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999");
	//cout << test << endl;
	//while (/*i++ == 0*/true) { //ENDLOS SCHLEIFE
		try {
			// Anzahl der Programmparameter überprüfen
			if (argc != 3) {
				// Fehlermeldung
				cout << "Wrong parameters! Allowed ones (for example):\n\n-> \"filename.exe input.txt output.txt\")" << endl;
			}
			else {
				//createFile();
				// get filewriter for the output
				FileOutput* out = FileOutput::getInstance();
				// Logdatei aus Programmparameter festsetzen
				out->setFile(argv[2]);

				//symtable	= 0;
				//fsm		= 0;

				// Symboltabelle erzeugen
				symtable	= new Symtable(SYMTABLE_ARRAY_SIZE);
				// Automaten erzeugen
				fsm			= new ScannerFSM(symtable);
				// Inputdatei aus Programmparameter setzen
				fsm->setFile(argv[1], BUFFER_BLOCK_SIZE);
				
				// Zeiger für die Tokens
				Token* currentToken = 0;

				do {				
					try {
						// Nächstes Token aus dem Automaten holen
						currentToken = fsm->getNextToken();					
						
						// Wenn es sich nicht um den NULL Zeiger handelt (EOF)
						if(currentToken != NULL) {
							// Token in der Datei loggen
							out->writeToken(currentToken);
							//std::cout << *currentToken << std::endl;
							// Token löschen
							delete currentToken;
						}
						
					}
					
					// Syntaxfehler
					catch (ScannerFSMSyntaxException e){
						fprintf(stderr, "%s %d:%d Lexem: %s\n", e.getMessage(), e.getLine(), e.getColumn(), e.getLexem());
						//cout << "Error: " << e.getMessage() << e.getLine() << ":" << e.getColumn() << " near to: " << "\"" << e.getLexem() << "\"" << std::endl;
						// Zeiger auf eins setzen, damit die Bedingung der While Schleife erhalten bleibt
						currentToken = (Token*) 1;
					}
					
				}while(currentToken);

				//symtable->printSymtable();

				//cout << endl << endl << fsm->getCounter();

				//std::cout.precision(10);
				//std::cout << strtod("615.1729342", &pos) << std::endl;
			}
		}
		catch(ScannerFSMException e) {
			cout << e.getMessage() << endl;
		}		
		catch(BufferException e) {
			cout << e.getMessage() << endl;
		}

		if (fsm != NULL) {
			delete fsm;
		}

		if (symtable != NULL) {
			delete symtable;
		}
			
	//}// -- ENDLOS SCHLEIFE

	// Benutzer bestimmt Programmabbruch
	cout << std::endl << std::endl << "Druecken sie Enter um das Programm zu beenden!";
	cin.get();

	return 0;
}
